package com.birdboot.core;

import com.birdboot.annotations.Controller;
import com.birdboot.annotations.RequestMapping;
import com.birdboot.controller.UserController;
import com.birdboot.http.HttpServletRequest;
import com.birdboot.http.HttpServletResponse;

import javax.activation.MimetypesFileTypeMap;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URISyntaxException;

/**
 * V8新增：
 * DispatcherServlet是由SpringMVC框架提供的一个Servlet类，用于Tomcat整合使用的类
 * 具体是接收处理请求的工作
 */
public class DispatcherServlet {
    //单例模式 (1)只需要一个实例、实例没有特殊属性（2）实例开销特别大
    private DispatcherServlet(){}
    private static DispatcherServlet instance = new DispatcherServlet();
    public static DispatcherServlet getInstance(){
        return instance;
    }

    private static File baseDir;
    private static File staticFile;
    static {
        try {
            baseDir = new File(DispatcherServlet.class.getClassLoader().getResource(".").toURI());// 定位类加载路径（固定写法）
            staticFile = new File(baseDir,"static");// 根据类加载路径定位static目录
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

    public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
//        String path = request.getUri();
//        不能使用getUri()了，这里可能含有参数，而参数不是固定信息
        String path = request.getRequestURI();
        System.out.println("抽象路径：" + path);

        // 判断本次请求是否为请求业务
        /*
        V17新增：使用动态机制动态调用需要的业务
         */
        try {
            File dir = new File(baseDir,"com/birdboot/controller");
            String packName = "com.birdboot.controller";
            File[] subs = dir.listFiles(f -> f.getName().endsWith(".class"));
            for (File sub : subs) {
                // 根据class文件名来获取类名
                String fileName = sub.getName();
                String className = fileName.substring(0, fileName.indexOf("."));// substring(beginIndex,endIndex);;;indexOf(".")返回"."的数组下标
                Class cls = Class.forName(packName + "." + className);

                // 判断该类是否被注解@Contoller标注
                if (cls.isAnnotationPresent(Controller.class)) {
                    // Object obj = cls.newInstance();
                    // 扫描里面所有的方法，并找到有注解@RequsetMapping的方法
                    Method[] methods = cls.getDeclaredMethods();
                    for (Method method : methods) {
                        if (method.isAnnotationPresent(RequestMapping.class)) {//判断是否被注解@RequestMapping修饰
                            // 通过@RequestMmapping注解获取上面的参数（即该方法的请求路径）
                            RequestMapping rm = method.getAnnotation(RequestMapping.class);
                            String value = rm.value();
                            // 判断本次请求路径是否与该参数值一致，如果是则说明本次请求由该方法处理
                            if (path.equals(value)){
                                // 实例化这个Controller
                                Object obj = cls.newInstance();
                                // 调用该方法处理本次请求
                                method.invoke(obj,request,response);
                                // 处理完毕之后return，避免执行下面处理静态资源的逻辑
                                return;
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        File file = new File(staticFile, path);
        if (file.isFile()) {
            response.setContentFile(file);
            response.addHeader("Server", "BirdBoot");
        } else {
            response.setStatusCode(404);
            response.setStatusReason("NotFound");          // 状态代码
            file = new File(staticFile, "404.html");   // 状态描述
            response.setContentFile(file);// 不用设置Content-Type和 Content-Length了，应为在setContentFile中只要有正文就会设置
            response.addHeader("Server", "BirdBoot");
        }
    }
}
